﻿using System;
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.Windows.Media.Imaging;
using System.Windows;
using Emgu.CV;
using System.Drawing;
using System.Drawing.Imaging;

namespace iMapa.Utils
{
    static public class ImgUtils
    {
        /// <summary>
        /// Delete a GDI object
        /// </summary>
        /// <param name="o">The poniter to the GDI object to be deleted</param>
        /// <returns></returns>
        [DllImport("gdi32")]
        private static extern int DeleteObject(IntPtr o);

        /// <summary>
        /// Convert an IImage to a WPF BitmapSource. The result can be used in the Set Property of Image.Source
        /// </summary>
        /// <param name="image">The Emgu CV Image</param>
        /// <returns>The equivalent BitmapSource</returns>
        public static BitmapSource ToBitmapSource(IImage image)
        {
            using (System.Drawing.Bitmap source = image.Bitmap)
            {
                IntPtr ptr = source.GetHbitmap(); //obtain the Hbitmap

                BitmapSource bs = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
                    ptr,
                    IntPtr.Zero,
                    Int32Rect.Empty,
                    System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());

                DeleteObject(ptr); //release the HBitmap
                return bs;
            }
        }

        public static Bitmap GetBitmap(BitmapSource source)
        {
            Bitmap bmp = new Bitmap(
              source.PixelWidth,
              source.PixelHeight,
              PixelFormat.Format32bppPArgb);
            BitmapData data = bmp.LockBits(
              new Rectangle(System.Drawing.Point.Empty, bmp.Size),
              ImageLockMode.WriteOnly,
              PixelFormat.Format32bppPArgb);
            source.CopyPixels(
              Int32Rect.Empty,
              data.Scan0,
              data.Height * data.Stride,
              data.Stride);
            bmp.UnlockBits(data);
            return bmp;
        }
        
        internal static class NativeMethods
        {
            [DllImport("gdi32.dll")]
            [return: MarshalAs(UnmanagedType.Bool)]
            internal static extern bool DeleteObject(IntPtr hObject);
        }


        public static PointF[] getCornerPoints(System.Drawing.Size modelImageSize)
        {
           PointF[] pts = new PointF[] { 
                new PointF(0, modelImageSize.Height),
                new PointF(modelImageSize.Width, modelImageSize.Height),
                new PointF(modelImageSize.Width, 0),
                new PointF(0, 0)};
           return pts;
        }

        public static System.Drawing.Point[] pointfToPoint(PointF[] pointf)
        {
            System.Drawing.Point[] pts = new System.Drawing.Point[] { 
                new System.Drawing.Point((int)pointf[0].X, (int) pointf[0].Y),
                new System.Drawing.Point((int)pointf[1].X, (int) pointf[1].Y),
                new System.Drawing.Point((int)pointf[2].X, (int) pointf[2].Y),
                new System.Drawing.Point((int)pointf[3].X, (int) pointf[3].Y)};
            return pts;
        }

        public static PointF ToPointF(System.Drawing.Point p)
        {
            return new PointF(p.X, p.Y);
        }
        
        public static System.Drawing.Point ToPoint(System.Drawing.PointF p)
        {
            return new System.Drawing.Point((int)p.X,(int) p.Y);
        }

        public static HomographyMatrix CountHomography(PointF[] src, PointF[] dst)
        {
            HomographyMatrix hom = new HomographyMatrix();

            CvInvoke.cvFindHomography(PointsToMat(src), PointsToMat(dst), hom.Ptr, Emgu.CV.CvEnum.HOMOGRAPHY_METHOD.DEFAULT, 2.0, IntPtr.Zero);
            return hom;
        }
        
        private static IntPtr PointsToMat(PointF[] p)
        {
            Matrix<double> src = new Matrix<double>(4, 2);
            for (int i = 0; i < 4; i++)
            {
                src.Data[i, 0] = p[i].X;
                src.Data[i, 1] = p[i].Y;
            }
            return src.Ptr;
        }

        public static bool IsImagesSame(Image<Emgu.CV.Structure.Bgr, byte> i1, Image<Emgu.CV.Structure.Bgr, byte> i2)
        {
            if (i1 == null || i2 == null || i1.Data==null ||i2.Data==null)
            {
                return true;
            } 
            
            byte[, ,] data1 = i1.Data;
            byte[, ,] data2 = i2.Data;
            
            if(i1.Width == i2.Width && i1.Height==i2.Height){

                for (int row = 0; row < i1.Height-1;row+=10)
                {
                    for (int col = 0; col < i1.Width-1; col+=10)
                    {
                        if (data1[row, col, 0] != data2[row, col, 0])
                        {
                            return false;
                        }
                    }
                }
                return true;
            }else{
                return false;
            }
        }

        public static double CountAvgDistance(PointF[] p, PointF[] p2)
        {
            double l = 0;
            for (int i = 0; i < p.Length; i++)
            {
                l = l + CountDistance(p[i],p2[i]);
            }
            return l / p.Length;
        }


        public static double CountDistance(PointF p, PointF p2)
        {
            double l = Math.Sqrt(Math.Pow(Math.Abs(p.X - p2.X), 2.0) + Math.Pow(Math.Abs(p.Y - p2.Y), 2.0));
            return l;
        }

        public static double CountDistance(System.Drawing.Point p, System.Drawing.Point p2)
        {
            double l = Math.Sqrt(Math.Pow(Math.Abs(p.X - p2.X), 2.0) + Math.Pow(Math.Abs(p.Y - p2.Y), 2.0));
            return l;
        }
    }
}
